home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / elv18src.zip / vmsio.c < prev    next >
C/C++ Source or Header  |  1993-08-07  |  19KB  |  675 lines

  1. /*
  2.    VMSIO.C -- replacements for lseek(), read() and close() to allow
  3.               arbitrary byte seeks with non-stream-lf files.
  4.              
  5.    (The original version (file routines) were written to port the
  6.     unix ``less'' program.  This version helps with the elvis port.
  7.     It may be useful elsewhere to port other utilities.)
  8.  
  9.    Written by John Campbell  CAMPBELL@NAUVAX.bitnet.   Use as you
  10.    wish, but leave me some credit for killing myself on this when
  11.    I was sick one weekend, ok?
  12.  
  13.    Also, added vms_rename as a weak replacment for link().  4/2/91
  14.    ...and because there was a routine named delete, created a vms_delete.
  15.  
  16.    Sigh, Steve wanted pipe stuff, so vms_rpipe(), vms_pread() and
  17.    vms_pclose() was born.                                   8/2/91
  18.  
  19.    Moved the tty i/o routines into this module as well.  vms_open_tty()
  20.    and vms_ttyread()  (ttread)                              8/2/91
  21. */
  22.  
  23. /*
  24. Entry points:
  25.  
  26. FILE I/O
  27. vms_close (fd)
  28. long vms_lseek (fd, offset, direction)
  29. int vms_read (fd, buf, len)
  30. int vms_rename (from, to)
  31. vms_delete (file)
  32.  
  33. PIPE I/O
  34. int vms_rpipe (cmd, fd, input_file)
  35. int vms_pread (pfile, buffer, size)
  36. int vms_rpclose(pfile)
  37.  
  38. TERMINAL I/O
  39. vms_open_tty()
  40. vms_ttyread(buf, len, time)
  41. */
  42. static char *version = "VMSIO, version 1.0";
  43.  
  44. #include <stdio.h>
  45. #include <errno.h>
  46. #include <perror.h>
  47. #define BUFSIZE 4096
  48.  
  49. /* Data and buffers used to implement vms_lseek() and vms_read() */
  50.    static struct {
  51.       int type, cur_loc, size, lastbin, maxbin, offset, eob;
  52.    } fdints[_NFILE] =
  53.       {{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},
  54.        {0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},
  55.        {0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},
  56.        {0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},
  57.        {0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1}};
  58.    static char **fdbufs[_NFILE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  59. typedef struct {
  60.         int loc, bstart, bend;
  61. } seeks;
  62.    static seeks *fdseeks[_NFILE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  63.  
  64. /* Intended use for fdseeks:  fdseeks[fd][i] for i'th triple */
  65.  
  66. #define G_cur_loc  fdints[fd].cur_loc
  67. #define G_size     fdints[fd].size
  68. #define G_eof_seen fdints[fd].eof_seen
  69. #define G_offset   fdints[fd].offset
  70. #define G_eob      fdints[fd].eob
  71.  
  72.  
  73. vms_close (fd)
  74. int fd;
  75. {
  76.    if (fd >= 0) {
  77.    /* Reset fdints[fd] and free any buffers we were using. */
  78.       fdints[fd].type    = 0;
  79.       fdints[fd].cur_loc = 0;
  80.       fdints[fd].size    = 0;
  81.       fdints[fd].lastbin = 0;
  82.       fdints[fd].maxbin  = 0;
  83.       fdints[fd].offset  = 0;
  84.       fdints[fd].eob     = -1;
  85.  
  86.       if (fdseeks[fd])
  87.          fdseeks[fd] = free (fdseeks[fd]);
  88.       if (fdbufs[fd])
  89.          fdbufs[fd]  = free (fdbufs[fd]);
  90.    }
  91.    return (close(fd));
  92. }
  93.  
  94. long vms_lseek (fd, offset, direction)
  95. int fd, offset, direction;
  96. {
  97.    int tmp;
  98.  
  99.    if (fd > _NFILE) {
  100.       fprintf (stderr,"Too many files for vms_lseek\n");
  101.       exit(2);
  102.    }
  103.    if (fd < 0) {
  104.       return lseek (fd, offset, direction);
  105.    }
  106.    if (fdints[fd].type == 0)
  107.       _init(fd);
  108.    if (fdints[fd].type == 1)
  109.       return lseek (fd, offset, direction);
  110.  
  111. /* Convert the possibly relative `offset' to an absolute offset. */
  112.    if (direction == 1) {
  113.       offset = G_cur_loc + offset + G_offset;
  114.    }
  115.    else if (direction == 2) {
  116.       if (G_eob == -1)
  117.          _refill (fd, -1);   /* Figure out the correct eob byte count */
  118.       offset = G_eob + offset;
  119.    }
  120.    if (offset < 0)
  121.       return -1;
  122.  
  123. /* Limitation of this implementation--only seeks to end of file. */
  124.    if (G_eob > -1 && offset > G_eob)
  125.       offset = G_eob;
  126.  
  127.    if (G_offset > offset || offset >= G_offset + G_size) {
  128.       if (_refill (fd, offset) == -1)
  129.          return -1;
  130.    }
  131.  
  132. /* Byte we want is now in our current buffer. */
  133.    G_cur_loc = offset - G_offset;
  134.  
  135. /* Sanity check. */
  136.    if (G_cur_loc < 0 || G_cur_loc > BUFSIZE)
  137.       _error ("G_cur_loc error in vms_lseek\n", 1);
  138.  
  139.    return G_cur_loc + G_offset;   /* Byte location in current buffer */
  140. }
  141.  
  142.  
  143. int vms_read (fd, buf, len)
  144. int fd, len;
  145. char *buf;
  146. {
  147. /* Buffer the read as the unix system would do. */
  148.    int  fill = 0, n, num = 0,tmp;
  149.    char *buffer;
  150.  
  151.    if (fd > _NFILE) {
  152.       fprintf (stderr,"Too many files for vms_read\n");
  153.       exit(2);
  154.    }
  155.  
  156.    if (fdints[fd].type == 0)
  157.       _init(fd);
  158.    if (fdints[fd].type == 1)
  159.       return read (fd, buf, len);
  160.  
  161.    buffer = fdbufs[fd];
  162.  
  163.    if (G_eob != -1 && G_cur_loc + G_offset >= G_eob)
  164.       return 0;   /* EOF */
  165.  
  166. /* Move any buffered data into place. */
  167.    while (len && G_cur_loc < G_size)  {
  168.       *buf++ = buffer[G_cur_loc++];
  169.       --len;
  170.       ++num;
  171.    }
  172. /* Refill as many buffers as necessary to put len bytes into buf. */
  173.    do {
  174.    /* Don't refill when asked to read beyond the end of the file. */
  175.       if (G_cur_loc == G_size && (G_eob == -1 || G_offset + G_size < G_eob)) {
  176.          if (_refill (fd, G_offset + G_size) == -1) return -1;
  177.       }
  178.       while (len && G_cur_loc < G_size)  {
  179.          *buf++ = buffer[G_cur_loc++];
  180.          --len;
  181.          ++num;
  182.       }
  183.    } while (len && (G_eob == -1 || G_offset + G_size < G_eob));
  184. /* Sanity check. */
  185.    if (G_cur_loc < 0 || G_cur_loc > BUFSIZE)
  186.       _error ("G_cur_loc bad in vms_read", 1);
  187.  
  188.    return num;
  189. }
  190.  
  191. /*
  192.    Fill from the appropriate buffer.  Note that offset is a true byte
  193.    offset and needs to be converted to fdseeks[fd][i].loc before seeking.
  194.    This technique may, in fact, generalize to other machines.
  195. */
  196. static int _refill (fd, offset)
  197. int fd, offset;
  198. {
  199.    int n, seekbin, tmp;
  200.    char *buffer = fdbufs[fd];
  201.  
  202. /* See if the offset is in our current buffer (eob offset is a pain). */
  203.    if (offset > 0 && G_eob > -1 && offset >= G_eob)
  204.       offset = G_eob - 1;
  205.  
  206.    if (offset > 0 && G_offset <= offset && offset < G_offset + G_size)
  207.       return G_offset;
  208.  
  209.    seekbin = fdints[fd].lastbin;
  210.  
  211. /* Now see if the offset is known (already been read once). */
  212.    if (offset >= 0 && offset < fdseeks[fd][seekbin].bstart) {
  213.    /* Yes!  We can seek to a known point to pick up this offset. */
  214.       while (seekbin > 0) {
  215.          if (offset >= fdseeks[fd][seekbin].bstart)
  216.            break;
  217.          --seekbin;
  218.       }
  219.    }
  220. /* Position ourselves for the read (even if we are already there?) */
  221. /* We can avoid this lseek if G_offset == [seekbin-1].bstart */
  222.    if (lseek (fd, fdseeks[fd][seekbin].loc, 0) == -1)
  223.       _error ("bad seek in _refill");
  224.  
  225. /* Ok, fill this buffer. */
  226. more:
  227.    G_cur_loc = 0;
  228.    G_size = 0;
  229.    G_offset = fdseeks[fd][seekbin].bstart;
  230.  
  231. /*
  232.    Don't want to be left with a partial record.  Choices are to shrink
  233.    down the read size or to keep seeking so we can backup to just before
  234.    n == read size.  Which seems faster?  Which puts an arbitrary limit
  235.    on the record size?
  236. */
  237.    /* Some lines longer than 512 may be truncated. */
  238.       while (G_size < BUFSIZE - 512 &&
  239.                 (n = read (fd, &buffer[G_size], BUFSIZE - G_size)) > 0) {
  240. #ifdef OTHERMETHOD
  241.          if (n == BUFSIZE - G_size)
  242.             break;   /* Don't count last line (it may be a partial line) */
  243. #endif
  244.          G_size += n;
  245.       }
  246.       if (n == 0) {
  247.          if (G_size == 0)
  248.             ++G_size;
  249.          G_eob = G_offset + G_size;
  250.          offset = G_eob;
  251.       }
  252.       else if (n == -1) {
  253.          _error ("vms_read (_refill) error", 0);
  254.          return -1;
  255.       }
  256.  
  257. /* Update the seek array.  Finish current bin and start next bin. */
  258.    if (G_size == 0)
  259.       ++G_size;
  260.    tmp = G_offset + G_size - 1;
  261.    if (seekbin < fdints[fd].lastbin && fdseeks[fd][seekbin].bend != tmp) {
  262.       fprintf (stderr, "Consistency failure in _refill\n");
  263.       exit(2);
  264.    }
  265.    fdseeks[fd][seekbin].bend = tmp;
  266.    if (G_eob == -1 || G_offset + G_size < G_eob) {
  267.    /* Set up the next seek bin */
  268.       if (++seekbin > fdints[fd].maxbin) {
  269.       /* Make more room. */
  270.          fdints[fd].maxbin = 2*fdints[fd].maxbin;
  271.          fdseeks[fd] = (void *)realloc (fdseeks[fd], fdints[fd].maxbin);
  272.       }
  273.  
  274.    /* Make sure that lastbin is up to date. */
  275.       if (seekbin > fdints[fd].lastbin) fdints[fd].lastbin = seekbin;
  276.  
  277.       if ((tmp = lseek(fd,0,1)) == -1)
  278.          _